package ongd.negocio.gestion;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 * Clase que corresponde a la entidad Persona de la base
 * de datos.
 *
 * @author <a href="mailto:egi0002@alu.ubu.es">Elena García Iglesias</a>
 * @author <a href="mailto:cms0021@alu.ubu.es">Cristina Martínez Sanz</a>
 * @version 1.0 20120124
 *
 */
@Entity
@Table(name = "persona")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Persona.findAll", query = "SELECT p FROM Persona p"),
    @NamedQuery(name = "Persona.findByDni", query = "SELECT p FROM Persona p WHERE p.dni = :dni"),
    @NamedQuery(name = "Persona.findByNombre", query = "SELECT p FROM Persona p WHERE p.nombre = :nombre"),
    @NamedQuery(name = "Persona.findByApellidos", query = "SELECT p FROM Persona p WHERE p.apellidos = :apellidos"),
    @NamedQuery(name = "Persona.findByFechaNacimiento", query = "SELECT p FROM Persona p WHERE p.fechaNacimiento = :fechaNacimiento"),
    @NamedQuery(name = "Persona.findByDomicilio", query = "SELECT p FROM Persona p WHERE p.domicilio = :domicilio"),
    @NamedQuery(name = "Persona.findByTelefono", query = "SELECT p FROM Persona p WHERE p.telefono = :telefono"),
    @NamedQuery(name = "Persona.findByEmail", query = "SELECT p FROM Persona p WHERE p.email = :email"),
    @NamedQuery(name = "Persona.findByDomiciliacion", query = "SELECT p FROM Persona p WHERE p.domiciliacion = :domiciliacion"),
    @NamedQuery(name = "Persona.findByNCuenta", query = "SELECT p FROM Persona p WHERE p.nCuenta = :nCuenta"),
    @NamedQuery(name = "Persona.findByCantidad", query = "SELECT p FROM Persona p WHERE p.cantidad = :cantidad"),
    @NamedQuery(name = "Persona.findByFechaRegistro", query = "SELECT p FROM Persona p WHERE p.fechaRegistro = :fechaRegistro"),
    @NamedQuery(name = "Persona.findByFechaBaja", query = "SELECT p FROM Persona p WHERE p.fechaBaja = :fechaBaja"),
    @NamedQuery(name = "Persona.findByActivo", query = "SELECT p FROM Persona p WHERE p.activo = :activo"),
    @NamedQuery(name = "Persona.findByActividadesPrincipales", query = "SELECT p FROM Persona p WHERE p.actividadesPrincipales = :actividadesPrincipales"),
    @NamedQuery(name = "Persona.findByTipo", query = "SELECT p FROM Persona p WHERE p.tipo = :tipo")})
public class Persona extends Entidad implements Serializable {

    /**
     * Identificador de la cuota.
     */
    private static final long serialVersionUID = 1L;
    /**
     * Atributo que corresponde con el dni de la persona.
     */
    @Id
    @Basic(optional = false)
    @Column(name = "DNI")
    private String dni;
    /**
     * Atributo que corresponde con el nombre de la persona.
     */
    @Basic(optional = false)
    @Column(name = "Nombre")
    private String nombre;
    /**
     * Atributo que corresponde con los apellidos de la persona.
     */
    @Basic(optional = false)
    @Column(name = "Apellidos")
    private String apellidos;
    /**
     * Atributo que corresponde con la fecha de nacimiento de la persona.
     */
    @Column(name = "Fecha_Nacimiento")
    @Temporal(TemporalType.DATE)
    private Date fechaNacimiento;
    /**
     * Atributo que corresponde con el domicilio de la persona.
     */
    @Column(name = "Domicilio")
    private String domicilio;
    /**
     * Atributo que corresponde con el telefono de la persona.
     */
    @Column(name = "Telefono")
    private String telefono;
    /**
     * Atributo que corresponde con el email de la persona.
     */
    @Column(name = "Email")
    private String email;
    /**
     * Atributo que indica si la persona va a domiciliar los pagos.
     */
    @Column(name = "Domiciliacion")
    private Boolean domiciliacion;
    /**
     * Atributo que corresponde con el numero de cuenta de la persona.
     */
    @Column(name = "NCuenta")
    private String nCuenta;
    /**
     * Atributo que corresponde con la cantidad anual que va a pagar la persona.
     */
    @Column(name = "Cantidad")
    private Double cantidad;
    /**
     * Atributo que corresponde con la fecha de registro de la persona.
     */
    @Basic(optional = false)
    @Column(name = "Fecha_Registro")
    @Temporal(TemporalType.DATE)
    private Date fechaRegistro;
    /**
     * Atributo que corresponde con la fecha de baja de la persona.
     */
    @Column(name = "Fecha_Baja")
    @Temporal(TemporalType.DATE)
    private Date fechaBaja;
    /**
     * Atributo que indica si la persona está activa.
     */
    @Column(name = "Activo")
    private Boolean activo;
    /**
     * Atributo que corresponde con las actividades principales de la persona.
     */
    @Column(name = "Actividades_Principales")
    private String actividadesPrincipales;
    /**
     * Atributo que corresponde con el tipo de la persona.
     */
    @Basic(optional = false)
    @Column(name = "Tipo")
    private String tipo;
    /**
     * Atributo que corresponde con la lista de proyectos en los que participa la persona.
     */
    @JoinTable(name = "persona_has_proyecto", joinColumns = {
        @JoinColumn(name = "Persona_DNI", referencedColumnName = "DNI")}, inverseJoinColumns = {
        @JoinColumn(name = "Proyecto_idProyecto", referencedColumnName = "idProyecto")})
    @ManyToMany
    private List<Proyecto> proyectoList;
    /**
     * Atributo que corresponde con la lista de apadrinados que tiene la persona.
     */
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "personaDNI")
    private List<Apadrinado> apadrinadoList;
    /**
     * Atributo que corresponde con la lista de cuotas de la persona.
     */
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "persona")
    private List<Cuota> cuotaList;
    /**
     * Atributo que corresponde con la lista de fraccionados de la persona.
     */
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "persona")
    private List<Fraccionado> fraccionadoList;

    /**
     * Constructor de la clase.
     */
    public Persona() {
    }

    /**
     * Constructor de la clase.
     * @param dni dni de la persona. 
     */
    public Persona(String dni) {
        this.dni = dni;
    }

    /**
     * Constructor de la clase.
     * @param dni dni de la persona.
     * @param nombre nombre de la persona.
     * @param apellidos apellidos de la persona.
     * @param fechaRegistro fecha de registro de la persona.
     * @param tipo tipo de persona. 
     */
    public Persona(String dni, String nombre, String apellidos, Date fechaRegistro, String tipo) {
        this.dni = dni;
        this.nombre = nombre;
        this.apellidos = apellidos;
        this.fechaRegistro = fechaRegistro;
        this.tipo = tipo;
    }

    /**
     * Método que devuelve el dni de la persona.
     * @return dni.
     * @see #setDni
     */
    public String getDni() {
        return dni;
    }

    /**
     * Método que asigna un nuevo dni a la persona.
     * @param dni Nuevo valor de la variable
     * @see #getDni
     */
    public void setDni(String dni) {
        this.dni = dni;
    }

    /**
     * Método que devuelve el nombre de la persona.
     * @return nombre.
     * @see #setNombre
     */
    public String getNombre() {
        return nombre;
    }

    /**
     * Método que asigna un nuevo nombre a la persona.
     * @param nombre Nuevo valor de la variable
     * @see #getNombre
     */
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    /**
     * Método que devuelve los apellidos de la persona.
     * @return apellidos
     * @see #setApellidos
     */
    public String getApellidos() {
        return apellidos;
    }

    /**
     * Método que asigna nuevos apellidos a la persona.
     * @param apellidos Nuevo valor de la variable
     * @see #getApellidos
     */
    public void setApellidos(String apellidos) {
        this.apellidos = apellidos;
    }

    /**
     * Método que devuelve la fecha de nacimiento de la persona.
     * @return fechaNacimiento.
     * @see #setFechaNacimiento
     */
    public Date getFechaNacimiento() {
        return fechaNacimiento;
    }

    /**
     * Método que asigna una nueva fecha de nacimiento a la persona.
     * @param fechaNacimiento Nuevo valor de la variable
     * @see #getFechaNacimiento
     */
    public void setFechaNacimiento(Date fechaNacimiento) {
        this.fechaNacimiento = fechaNacimiento;
    }

    /**
     * Método que devuelve el domicilio de la persona.
     * @return domicilio.
     * @see #setDomicilio
     */
    public String getDomicilio() {
        return domicilio;
    }

    /**
     * Método que asigna un nuevo domicilio a la persona.
     * @param domicilio Nuevo valor de la variable
     * @see #getDomicilio
     */
    public void setDomicilio(String domicilio) {
        this.domicilio = domicilio;
    }

    /**
     * Método que devuelve el telefono de la persona.
     * @return telefono.
     * @see #setTelefono
     */
    public String getTelefono() {
        return telefono;
    }

    /**
     * Método que asigna un nuevo telefono a la persona.
     * @param telefono Nuevo valor de la variable
     * @see #getTelefono
     */
    public void setTelefono(String telefono) {
        this.telefono = telefono;
    }

    /**
     * Método que devuelve el email de la persona.
     * @return email.
     * @see #setEmail
     */
    public String getEmail() {
        return email;
    }

    /**
     * Método que asigna un nuevo email a la persona.
     * @param email Nuevo valor de la variable
     * @see #getEmail
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * Método que devuelve si la persona v a domiciliar los pagos.
     * @return true si v a adomiciliarlos o false si no es así. 
     * @see #setDomiciliacion
     */
    public Boolean getDomiciliacion() {
        return domiciliacion;
    }

    /**
     * Método que asigna un nuevo valor a la domiciliación de la persona.
     * @param domiciliacion Nuevo valor de la variable
     * @see #getDomiciliacion
     */
    public void setDomiciliacion(Boolean domiciliacion) {
        if (esSocio() || esPadrino()) {
            this.domiciliacion = domiciliacion;
        }
    }

    /**
     * Método que devuelve el numero de cuenta de la persona.
     * @return nCuenta.
     * @see #setNCuenta
     */
    public String getNCuenta() {
        return nCuenta;
    }

    /**
     * Método que asigna un nuevo numero de cuenta a la persona.
     * @param nCuenta Nuevo valor de la variable
     * @see #getNCuenta
     */
    public void setNCuenta(String nCuenta) {
        if (esSocio() || esPadrino()) {
            this.nCuenta = nCuenta;
        }
    }

    /**
     * Método que devuelve la cantidad de la persona.
     * @return cantidad.
     * @see #setCantidad
     */
    public Double getCantidad() {
        return cantidad;
    }

    /**
     * Método que asigna una nueva cantidad a la persona.
     * @param cantidad Nuevo valor de la variable
     * @see #getCantidad
     */
    public void setCantidad(Double cantidad) {
        if (esSocio() || esPadrino() ) {
            this.cantidad = cantidad;
        }
    }

    /**
     * Método que devuelve la fecha de registro de la persona.
     * @return fechaRegistro.
     * @see #setFechaRegistro
     */
    public Date getFechaRegistro() {
        return fechaRegistro;
    }

    /**
     * Método que asigna una nueva fecha de registro a la persona.
     * @param fechaRegistro Nuevo valor de la variable
     * @see #getFechaRegistro
     */
    public void setFechaRegistro(Date fechaRegistro) {
        this.fechaRegistro = fechaRegistro;
    }

    /**
     * Método que devuelve la fecha de baja de la persona.
     * @return fechaBaja. 
     * @see #setFechaBaja
     */
    public Date getFechaBaja() {
        return fechaBaja;
    }

    /**
     * Método que asigna una nueva fecha de baja a la persona.
     * @param fechaBaja Nuevo valor de la variable
     * @see #getFechaBaja
     */
    public void setFechaBaja(Date fechaBaja) {
        if (esSocio() || esPadrino()) {
            this.fechaBaja = fechaBaja;
        }
    }

    /**
     * Método que devuelve si la persona está activa.
     * @return true si está activa o false si no es así.
     * @see #setActivo
     */
    public Boolean getActivo() {
        return activo;
    }

    /**
     * Método que asigna un nuevo valor a la variable que indica si la persona está activa.
     * @param activo Nuevo valor de la variable
     * @see #getActivo
     */
    public void setActivo(Boolean activo) {
        if (esVoluntario()) {
            this.activo = activo;
        }
    }

    /**
     * Método que devuelve las actividades principales de la persona.
     * @return actividadesPrincipales.
     * @see #setActividadesPrincipales
     */
    public String getActividadesPrincipales() {
        return actividadesPrincipales;
    }

    /**
     * Método que asigna unas actividades principales nuevas a la persona.
     * @param actividadesPrincipales Nuevo valor de la variable
     * @see #getActividadesPrincipales
     */
    public void setActividadesPrincipales(String actividadesPrincipales) {
        if (esVoluntario()) {
            this.actividadesPrincipales = actividadesPrincipales;
        }
    }

    /**
     * Método que devuelve el tipo de la persona.
     * @return tipo.
     * @see #setTipo
     */
    public String getTipo() {
        return tipo;
    }

    /**
     * Método que asigna un nuevo tipo a la persona.
     * @param tipo Nuevo valor de la variable
     * @see #getTipo
     */
    public void setTipo(String tipo) {
        this.tipo = tipo;
    }

    /**
     * Método que devuelve la lista de proyectos de la persona.
     * @return proyectoList.
     * @see #setProyectoList
     */
    @XmlTransient
    public List<Proyecto> getProyectoList() {
        return proyectoList;
    }

    /**
     * Método que asigna una nueva lista de proyectos a la persona.
     * @param proyectoList Nuevo valor de la variable
     * @see #getProyectoList
     */
    public void setProyectoList(List<Proyecto> proyectoList) {
        if (esPadrino()) {
            this.proyectoList = proyectoList;
        }
    }

    /**
     * Método que devuelve la lista de apadrinados de la persona.
     * @return apadrinadoList.
     * @see #setApadrinadoList
     */
    @XmlTransient
    public List<Apadrinado> getApadrinadoList() {
        return apadrinadoList;
    }

    /**
     * Método que asigna una nueva lista de apadrinados a la persona.
     * @param apadrinadoList Nuevo valor de la variable
     * @see #getApadrinadoList
     */
    public void setApadrinadoList(List<Apadrinado> apadrinadoList) {
        if (esPadrino()) {
            this.apadrinadoList = apadrinadoList;
        }
    }

    /**
     * Método que devuelve la lista de cuotas de la persona.
     * @return cuotaList.
     * @see #setCuotaList
     */
    @XmlTransient
    public List<Cuota> getCuotaList() {
        return cuotaList;
    }

    /**
     * Método que asigna una nueva lista de cuotas a la persona.
     * @param cuotaList Nuevo valor de la variable
     * @see #getCuotaList
     */
    public void setCuotaList(List<Cuota> cuotaList) {
        if (esSocio() || esPadrino()) {
            this.cuotaList = cuotaList;
        }
    }

    /**
     * Método que devuelve la lista de fraccionado de la persona.
     * @return fraccionadoList.
     * @see #setFraccionadoList
     */
    @XmlTransient
    public List<Fraccionado> getFraccionadoList() {
        return fraccionadoList;
    }

    /**
     * Método que asigna una nueva lista de fraccionados a la persona.
     * @param fraccionadoList Nuevo valor de la variable
     * @see #getFraccionadoList
     */
    public void setFraccionadoList(List<Fraccionado> fraccionadoList) {
        if (esSocio() || esPadrino()) {
            this.fraccionadoList = fraccionadoList;
        }
    }

    /**
     * Método que devuelve un número con una propiedad fundamental, si dos 
     * objetos son iguales el valor retornado por sus respectivos hashCode 
     * debe ser igual.
     * @return hash
     */
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (dni != null ? dni.hashCode() : 0);
        return hash;
    }

    /**
     * Método que compara si dos personas son iguales.
     * @param object Objeto a comparar
     * @return true o false
     */
    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Persona)) {
            return false;
        }
        Persona other = (Persona) object;
        if ((this.dni == null && other.dni != null) || (this.dni != null && !this.dni.equals(other.dni))) {
            return false;
        }
        return true;
    }

    /**
     * Método que devuelve una cadena con la persona.
     * @return string
     */
    @Override
    public String toString() {
        return "ongd.negocio.entidades.Persona[ dni=" + dni + " ]";
    }

    /**
     * Método que nos dice si la persona es socio.
     * @return true si es socio o false si es de otro tipo.
     */
    public boolean esSocio() {
        return (tipo.compareTo("S") == 0);
    }

    /**
     * Método que nos dice si la persona es padrino.
     * @return true si es padrino o false si es de otro tipo.
     */
    public boolean esPadrino() {
        return (tipo.compareTo("P") == 0);
    }

    /**
     * Método que nos dice si la persona es voluntario.
     * @return true si es voluntario o false si es de otro tipo.
     */
    public boolean esVoluntario() {
        return (tipo.compareTo("V") == 0);
    }
}
